<template>
  <div class="ly-form">
    <el-form
      ref="formDataRef"
      :model="formData"
      :rules="form.rules ?? []"
      :label-width="form.layout.labelWidth ?? '100px'"
      :size="form.layout.size ?? 'default'"
    >
      <el-row :gutter="10">
        <template v-for="(item, index) in form.items" :key="item.prop">
          <template v-if="showResult(index) && !isHiddenItem(item)">
            <el-col
              :md="form.layout.md"
              :sm="form.layout.sm"
              :xs="form.layout.xs"
              :span="item.span ?? 8"
            >
              <!--          普通输入框-->
              <template v-if="item.type === 'input'">
                <el-form-item
                  :required="item.required ?? false"
                  :label="item.label"
                  :prop="item.prop"
                >
                  <el-input
                    :placeholder="item.placeholder"
                    v-model="formData[item.prop]"
                  />
                </el-form-item>
              </template>
              <!--          密码框-->
              <template v-else-if="item.type === 'password' && !isEditBtn">
                <el-form-item :label="item.label" :prop="item.prop">
                  <el-input
                    :type="item.type"
                    :placeholder="item.placeholder"
                    v-model="formData[item.prop]"
                    show-password
                  />
                </el-form-item>
              </template>
              <!--          多行文本框-->
              <template v-else-if="item.type === 'textarea'">
                <el-form-item
                  style="align-items: flex-start"
                  :label="item.label"
                  :prop="item.prop"
                >
                  <el-input
                    type="textarea"
                    :rows="item.rows"
                    v-model="formData[item.prop]"
                    :placeholder="item.placeholder"
                  ></el-input>
                </el-form-item>
              </template>
              <!--          下拉框-->
              <template v-else-if="item.type === 'select'">
                <el-form-item :label="item.label" :prop="item.prop">
                  <el-select
                    style="width: 100%"
                    v-model="formData[item.prop]"
                    :placeholder="item.placeholder"
                    :size="item.size"
                    :disabled="isDisabledSelect(item)"
                    :filterable="item.filterSearch?.filterable ?? false"
                    :filter-method="item.filterSearch?.filterMethod"
                  >
                    <el-option
                      v-for="option in item.options"
                      :key="option.value"
                      :label="option.label"
                      :value="option.value"
                    />
                  </el-select>
                </el-form-item>
              </template>
              <!--          日期选择器（区间）-->
              <template v-else-if="item.type === 'date-picker'">
                <el-form-item :label="item.label" :prop="item.prop">
                  <el-date-picker
                    v-model="formData[item.prop]"
                    type="daterange"
                    range-separator="-"
                    start-placeholder="开始时间"
                    end-placeholder="结束时间"
                    :size="item.size"
                  />
                </el-form-item>
              </template>
              <!--          日期选择器（头尾）-->
              <template v-else-if="item.type === 'date-time-picker'">
                <template v-if="item.isBannedTime">
                  <el-form-item label="类型">
                    <el-radio-group v-model="isPermanent">
                      <el-radio :label="0">可选</el-radio>
                      <el-radio :label="1">永久</el-radio>
                    </el-radio-group>
                  </el-form-item>
                </template>
                <el-form-item :label="item.label" :prop="item.prop">
                  <el-date-picker
                    v-model="formData[item.prop]"
                    :size="item.size"
                    :disabled="!!isPermanent"
                    type="datetime"
                    :placeholder="item.placeholder"
                    @change="choiceTime(item.prop)"
                  />
                </el-form-item>
              </template>
              <!--          单选框组-->
              <template v-else-if="item.type === 'radio'">
                <el-form-item :label="item.label" :prop="item.prop">
                  <el-radio-group
                    v-model="formData[item.prop]"
                    :disabled="isDisabledItem(item)"
                  >
                    <template v-for="iitem in item.options" :key="iitem.value">
                      <el-radio :label="iitem.value"
                        >{{ iitem.label }}
                      </el-radio>
                    </template>
                  </el-radio-group>
                </el-form-item>
              </template>
              <!--          图片-->
              <template v-else-if="item.type === 'img'">
                <el-form-item :label="item.label" :prop="item.prop">
                  <img class="avatar" :src="formData[item.prop]" />
                </el-form-item>
              </template>
              <!--            自定义-插槽-->
              <template v-else-if="item.type === 'custom'">
                <el-form-item :label="item.label" :prop="item.prop">
                  <slot
                    :name="item.slotName"
                    v-bind="item"
                    :value="formData[item.prop]"
                  ></slot>
                </el-form-item>
              </template>
            </el-col>
          </template>
        </template>
        <!--按钮-->
        <template v-if="form.layout.isShowBtns ?? false">
          <el-col :offset="btnOffset" :span="8">
            <div class="btns">
              <el-button size="small" type="primary" @click="searchClick"
                >搜索
              </el-button>
              <el-button size="small" @click="resetClick">重置</el-button>
              <el-button
                size="small"
                link
                type="primary"
                @click="isShowingMore = !isShowingMore"
                >{{ isShowingMore ? ' 收起' : '展开' }}
                <el-icon style="margin-left: 3px">
                  <component :is="isShowingMore ? 'ArrowUp' : 'ArrowDown'" />
                </el-icon>
              </el-button>
            </div>
          </el-col>
        </template>
      </el-row>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import type {
  IBatchBtn,
  ILyForm,
  ILyFormItem,
  ISingleBtn
} from '@/global/types'
import { computed, reactive, ref, watch, watchEffect } from 'vue'
import type { FormInstance } from 'element-plus'
import { useGoodSkuStore, usePageCommonStore } from '@/store'
import { formatTime } from '@/utils/format'
import { storeToRefs } from 'pinia'

interface IProps {
  pageName?: string
  form: ILyForm
  btnType?: ISingleBtn | IBatchBtn // 当前的按钮类型，用于点击确定框传出去
  isEditBtn?: boolean // 由具体页面一层一层传进来用于判断当前是新增数据还是编辑数据，新增需要密码输入，编辑不需要
}

const props = withDefaults(defineProps<IProps>(), {
  isEditBtn: false
})

const formDataRef = ref<FormInstance>()
const pageCommonStore = usePageCommonStore()

const isShowingMore = ref(false)
const showResult = computed(() => {
  return (index: number) => {
    // 情况1：如果没有按钮那么一定是对话框或者抽屉表单，全都为true
    // 情况2：如果isShowingMore为true全部都应该展示，如果为false只有第一个表单显示
    if (isShowingMore.value || !props.form.layout?.isShowBtns) {
      return true
    } else return index === 0
  }
})
// 动态指定按钮左边的偏移量
// eslint-disable-next-line vue/return-in-computed-property
const btnOffset = computed(() => {
  if (!isShowingMore.value) return 8
  switch (props.form.items.length % 3) {
    case 0:
      return 16
    case 1:
      return 8
    case 2:
      return 0
  }
})

// ========================= 封禁时间单选框的问题 ===============================
const isPermanent = ref(0)
// 选择时间后
const choiceTime = (prop) => {
  // 有这两个字段的需要格式化时间
  if (prop === 'createTime' || prop === 'endTime' || prop === 'unlockTime') {
    formData[prop] = formatTime(formData[prop])
  }
  // 'createTime' in formData && (formData['createTime'] = formatTime(value))
}

// ====================== 动态指定formData的属性 ==========================
let initialData = {}
watch(
  () => props.form,
  () => {
    // 表单是动态的会残留上一个表单的属性，需要监听删除

    // 让时间选择重置为可以选中状态, 有可能上次禁用的状态还保留
    isPermanent.value = 0
  }
)
const formData = reactive(initialData)
watchEffect(() => {
  // 1.清除上一次残留的值再复制新的
  Object.keys(formData).forEach((key) => {
    Reflect.deleteProperty(formData, key)
  })

  // 2.针对编辑这种表单点开就有数据的情况
  const keys = Object.keys(pageCommonStore.curRow)
  if (keys.length >= 1 && !props.form.layout?.isShowBtns) {
    for (const item of props.form.items) {
      const value = pageCommonStore.curRow[item.prop as string]
      if (item.prop) {
        if (value || value === 0) {
          formData[item.prop] = value
        } else {
          formData[item.prop] = ''
        }
      }
    }
  } else {
    // 3.针对一般表单
    for (const item of props.form.items) {
      if (item.prop) initialData[item.prop] = ''
    }
  }
})

watch(
  () => pageCommonStore.imgUrl,
  () => {
    if ('headPortrait' in formData) {
      formData['headPortrait'] = pageCommonStore.imgUrl
    }
    if ('brandLogo' in formData) {
      formData['brandLogo'] = pageCommonStore.imgUrl
    }
    if ('img' in formData) {
      formData['img'] = pageCommonStore.imgUrl
    }
  }
)

// ===================== 计算属性 =============================
// 1.某些表单不需要显示
const isHiddenItem = computed(() => {
  // 注意1：当前只是做了普通input框的限制
  // 注意2：这里没有限制是不是头部高级搜索的框，因为菜单页没有高级搜索
  return (item: ILyFormItem) => {
    if (props.pageName === 'menu') {
      // 菜单页目录
      if (
        item.type === 'input' &&
        formData['type'] === '0' &&
        item.prop === 'url'
      )
        return true
      // 菜单页按钮
      if (
        item.type === 'input' &&
        formData['type'] === '2' &&
        (item.prop === 'name' || item.prop === 'url' || item.prop === 'path')
      )
        return true
    } else if (props.pageName === 'goodSku' && props.isEditBtn) {
      // 商品sku页面
      // 如果这个id不存在证明是规格的编辑,需要禁用部分item
      const id = pageCommonStore.curRow.specificationValueId
      const isSystem = pageCommonStore.curRow.productId === -1
      // 不是规格值的情况
      if (
        !id &&
        (item.prop === 'isShow' ||
          item.prop === 'name' ||
          item.prop === 'img' ||
          item.slotName === 'uploadImage' ||
          item.prop === 'specificationPrice')
      ) {
        return true
      }
      // 是规格值且是系统数据的情况
      if (
        id &&
        isSystem &&
        (item.prop === 'specificationPrice' ||
          item.prop === 'img' ||
          item.slotName === 'uploadImage' ||
          item.prop === 'specificationName')
      ) {
        return true
      }
      // 是规格值但不是系统数据的情况
      if (id && !isSystem && item.prop === 'specificationName') {
        return true
      }
    } else if (props.pageName === 'goodSku' && !props.isEditBtn) {
      // 新增的展示情况
      const isNewAll = !pageCommonStore.curRow.specificationId
      return !isNewAll && item.prop === 'specificationName'
    } else if (props.pageName === 'goodClassify') {
      if (item.prop === 'img' && formData['classifyType'] !== 2) {
        return true
      }
    } else {
      return false
    }
  }
})
// 2.某些表单需要禁用
const isDisabledItem = computed(() => {
  return (item: ILyFormItem) => {
    if (props.pageName !== 'menu') return false
    if (item.type === 'radio' && props.isEditBtn) return true
  }
})

// 3.某些下拉框需要禁用
const isDisabledSelect = computed(() => {
  return (item: ILyFormItem) => {
    if (props.pageName === 'goodClassify' && item.prop === 'classifyType')
      return true
    else {
      return (
        props.pageName === 'goodSku' &&
        item.prop === 'productId' &&
        !formData['merchantId']
      )
    }
  }
})

// ================ 商品sku页面 ==================
// 初始化下拉框（商户、商品）的数据
const goodSkuStore = useGoodSkuStore()
const { productList } = storeToRefs(goodSkuStore)
watchEffect(() => {
  if (
    props.pageName === 'goodSku' &&
    props.form.layout?.isShowBtns &&
    formData['merchantId']
  ) {
    formData['productId'] = ''
    goodSkuStore.getProductListAction(formData['merchantId'], '').then(() => {
      const productIdObj = props.form.items.find(
        (item) => item.prop === 'productId'
      )
      if (productIdObj) {
        productIdObj.options = productList.value
      }
    })
  }
})

// ====================== 向外暴露方法 =================================
// 暴露一个方法获取当前表单输入的内容
function getFormData() {
  // 1。如果当前表单是封禁时间并且是永久封禁类型，那么直接写死时间为-1，也就是永久
  isPermanent.value && (formData['bannedTime'] = -1)
  // 2.菜单页-新增和编辑
  if (props.pageName === 'menu' && formData['type'] === '2') {
    Reflect.deleteProperty(formData, 'name')
    Reflect.deleteProperty(formData, 'url')
    Reflect.deleteProperty(formData, 'path')
  }
  if (props.pageName === 'menu' && formData['type'] === '0') {
    Reflect.deleteProperty(formData, 'url')
  }
  if (props.pageName === 'menu' && props.isEditBtn) {
    Reflect.deleteProperty(formData, 'type')
  }
  if (props.pageName === 'goodClassify' && formData['classifyType'] !== 2) {
    Reflect.deleteProperty(formData, 'img')
  }
  return { ...formData }
}

// 暴露一个方法清空表单
function cleanFormData() {
  formDataRef.value?.resetFields()
}

// =========================== 子传父：将搜索和重置事件传出去 ===========================
const emits = defineEmits(['searchClick', 'resetClick'])
// 1.点击搜索按钮
const searchClick = () => {
  emits('searchClick', formData)
}
// 2.点击重置按钮
const resetClick = () => {
  formDataRef.value?.resetFields()
  usePageCommonStore().pagination.current = 1
  emits('resetClick')
}

defineExpose({ getFormData, cleanFormData })
</script>

<style scoped lang="less">
.ly-form {
  .btns {
    display: flex;
    align-items: center;
    justify-content: flex-end;
  }

  .el-form-item {
    padding: 0 20px;
    display: flex;
    align-items: center;
  }
}

.avatar {
  width: 80px;
  height: 80px;
  border-radius: 5px;
}
</style>
